/*
//
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//    Copyright (c) 2008 Intel Corporation. All Rights Reserved.
//
//
*/

#include "umc_defs.h"
#if defined(UMC_ENABLE_AVS_VIDEO_ENCODER)

#include "umc_avs_enc_processing_unit_me.h"
#include "umc_avs_enc_slice.h"

#include "umc_automatic_mutex.h"
#include "umc_mutex.h"

namespace UMC
{

AVSMEProcessingUnit::AVSMEProcessingUnit(void)
{

} // AVSMEProcessingUnit::AVSEncProcessingUnit(void)

AVSMEProcessingUnit::~AVSMEProcessingUnit(void)
{

} // AVSMEProcessingUnit::~AVSEncProcessingUnit(void)

Status AVSMEProcessingUnit::Init(Mutex *pGuard, BaseCodecParams *pCodecParams)
{
    m_avs_me.CopyEncoderParams(pCodecParams);
    return AVSProcessingUnit::Init(pGuard);
} // Status AVSMEProcessingUnit::Init(Mutex *pGuard, BaseCodecParams *pCodecParams)

bool AVSMEProcessingUnit::LoadJob(AVSListElement<AVSFrame> *pFrameList)
{
    eAVSPicStructure field = AVS_UPPER_FIELD;

    // run over frame list and find an unparsed slice
    while (pFrameList)
    {
        AVSEncSlice *pSlice;

        if (AVS_FRAME == pFrameList->m_picStructure)
        {
            pSlice = (AVSEncSlice *) pFrameList->m_Slices.GetHead();
        }
        else
        {
            pSlice = (AVSEncSlice *) pFrameList->GetPicture(field)->m_Slices.GetHead();
        }

        // run over slice list and find an unparsed slice
        while (pSlice)
        {
            if ((false == pSlice->m_bError) &&
                (pFrameList->ReferencesReady()) &&
                (pSlice->m_bMeVacant)  &&
                (pSlice->m_bDecVacant)  &&
                (pSlice->m_meCtx.MbIndex < pSlice->m_disCtx.MbLast))
            {
                m_pAVSME = &m_avs_me;

                m_pAVSME->SetMEContext(pSlice->m_meCtx);
                pSlice->m_bMeVacant = false;

                m_pAVSME->SetEncodingContext(pSlice->m_encCtx);
                pSlice->m_bDecVacant = false;

                return true;
            }

            pSlice = (AVSEncSlice *) pSlice->GetNext();
        }

        //get next frame only if both fields of the current were inspected
        if ((AVS_FRAME == pFrameList->m_picStructure) ||
            (AVS_LOWER_FIELD == field))
        {
            pFrameList = pFrameList->GetNext();
            field = AVS_UPPER_FIELD;
        }
        else
        {
            field = AVS_LOWER_FIELD;
        }
    }

    return false;

} // bool AVSMEProcessingUnit::LoadJob(AVSListElement<AVSFrame> *pFrameList)

Status AVSMEProcessingUnit::DoJob(void)
{
    Status umcRes;
    // do estimation
    //if (!m_pAVSME->isAVSMEInit)
    //    m_pAVSME->SetMEParams();

    switch (m_pAVSME->GetMEContext().m_pPicHeader->PictureType)
    {
    case AVS_I_PICTURE:
        umcRes = m_pAVSME->EstimateISlice();
        break;

    case AVS_P_PICTURE:
        umcRes = m_pAVSME->EstimatePSlice();
        break;

    default:
        umcRes = m_pAVSME->EstimateBSlice();
        break;
    };

    //switch (m_pAVSME->GetEncodingContext().m_pPicHeader->PictureType)
    //{
    //case AVS_I_PICTURE:
    //    m_pAVSME->EstimateIMacroBlocksRow();
    //    break;

    //case AVS_P_PICTURE:
    //    m_pAVSME->EstimatePMacroBlocksRow();
    //    break;

    //default:
    //    m_pAVSME->EstimateBMacroBlocksRow();
    //    break;
    //};

    // finalize processed task
    UnloadJob();

    return UMC_ERR_NOT_ENOUGH_DATA;

} // void AVSMEProcessingUnit::DoJob(void)

Status AVSMEProcessingUnit::HandleError(void)
{
    AutomaticMutex guard(m_pGuard->ExtractHandle());
    AVSSlice *pSlice;

    pSlice = m_pAVSME->GetMEContext().m_pSlice;

    // drop the slice's flags
    pSlice->m_bDecVacant = true;
    pSlice->m_bMeVacant = true;
    pSlice->m_bError = true;

    return UMC_ERR_NOT_ENOUGH_DATA;

} // void AVSMEProcessingUnit::HandleError(void)

void AVSMEProcessingUnit::UnloadJob(void)
{
    AVSEncSlice *pSlice;

    pSlice = (AVSEncSlice *) m_pAVSME->GetMEContext().m_pSlice;

    // reflect changes to the slice
    {
        AutomaticMutex guard(m_pGuard->ExtractHandle());

        pSlice->m_meCtx = m_pAVSME->GetMEContext();
        pSlice->m_bMeVacant = true;
        pSlice->m_bDecVacant = true;
    }

} // void AVSMEProcessingUnit::UnloadJob(void)

} // namespace UMC

#endif // defined(UMC_ENABLE_AVS_VIDEO_ENCODER)
